# -*- coding: utf-8 -*-
"""
浏览器管理模块
"""

import asyncio
import logging
import random
from typing import Optional, Dict, Any
from playwright.async_api import async_playwright, Browser, BrowserContext, Page

from config.settings import CRAWLER_CONFIG


class BrowserManager:
    """浏览器管理器"""
    
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        self.playwright = None
        self.browser: Optional[Browser] = None
        self.context: Optional[BrowserContext] = None
        self.page: Optional[Page] = None
        self.config = CRAWLER_CONFIG
    
    async def start(self, headless: bool = True) -> None:
        """启动浏览器"""
        try:
            self.playwright = await async_playwright().start()
            
            # 启动Chromium浏览器
            self.browser = await self.playwright.chromium.launch(
                headless=headless,
                args=[
                    '--no-sandbox',
                    '--disable-blink-features=AutomationControlled',
                    '--disable-web-security',
                    '--disable-features=VizDisplayCompositor'
                ]
            )
            
            # 创建浏览器上下文
            self.context = await self.browser.new_context(
                viewport={'width': 1920, 'height': 1080},
                user_agent=self._get_random_user_agent()
            )
            
            # 创建页面
            self.page = await self.context.new_page()
            
            # 设置页面超时 - 延长到90秒
            self.page.set_default_timeout(90000)
            
            self.logger.info("浏览器启动成功")
            
        except Exception as e:
            self.logger.error(f"浏览器启动失败: {e}")
            await self.close()
            raise
    
    async def close(self) -> None:
        """关闭浏览器"""
        try:
            if self.page:
                await self.page.close()
                self.page = None
            
            if self.context:
                await self.context.close()
                self.context = None
            
            if self.browser:
                await self.browser.close()
                self.browser = None
            
            if self.playwright:
                await self.playwright.stop()
                self.playwright = None
            
            self.logger.info("浏览器已关闭")
            
        except Exception as e:
            self.logger.error(f"关闭浏览器时出错: {e}")
    
    async def navigate_to(self, url: str, wait_for_load: bool = True) -> bool:
        """导航到指定URL"""
        try:
            if not self.page:
                raise RuntimeError("浏览器未启动")
            
            self.logger.info(f"导航到: {url}")
            
            # 访问页面 - 延长超时时间到90秒
            response = await self.page.goto(url, timeout=90000)

            if response.status != 200:
                self.logger.error(f"页面访问失败，状态码: {response.status}")
                return False

            if wait_for_load:
                # 等待页面加载完成 - 延长超时时间到90秒
                await self.page.wait_for_load_state('networkidle', timeout=90000)
                
                # 额外等待确保JavaScript执行完成
                await asyncio.sleep(2)
            
            self.logger.info("页面导航成功")
            return True
            
        except Exception as e:
            self.logger.error(f"页面导航失败: {e}")
            return False
    
    async def wait_for_element(self, selector: str, timeout: int = 10000) -> bool:
        """等待元素出现"""
        try:
            if not self.page:
                raise RuntimeError("浏览器未启动")
            
            await self.page.wait_for_selector(selector, timeout=timeout)
            return True
            
        except Exception as e:
            self.logger.warning(f"等待元素失败 {selector}: {e}")
            return False
    
    async def click_element(self, selector: str, timeout: int = 10000) -> bool:
        """点击元素"""
        try:
            if not self.page:
                raise RuntimeError("浏览器未启动")
            
            # 等待元素可见
            await self.page.wait_for_selector(selector, timeout=timeout)
            
            # 点击元素
            await self.page.click(selector)
            
            # 等待页面响应
            await asyncio.sleep(1)
            
            return True
            
        except Exception as e:
            self.logger.error(f"点击元素失败 {selector}: {e}")
            return False
    
    async def get_page_content(self) -> str:
        """获取页面内容"""
        try:
            if not self.page:
                raise RuntimeError("浏览器未启动")
            
            return await self.page.content()
            
        except Exception as e:
            self.logger.error(f"获取页面内容失败: {e}")
            return ""
    
    async def execute_script(self, script: str) -> Any:
        """执行JavaScript脚本"""
        try:
            if not self.page:
                raise RuntimeError("浏览器未启动")
            
            return await self.page.evaluate(script)
            
        except Exception as e:
            self.logger.error(f"执行脚本失败: {e}")
            return None
    
    async def take_screenshot(self, path: str = None) -> bytes:
        """截图"""
        try:
            if not self.page:
                raise RuntimeError("浏览器未启动")
            
            screenshot = await self.page.screenshot(
                path=path,
                full_page=True
            )
            
            if path:
                self.logger.info(f"截图已保存: {path}")
            
            return screenshot
            
        except Exception as e:
            self.logger.error(f"截图失败: {e}")
            return b""
    
    async def random_delay(self) -> None:
        """随机延时"""
        delay = random.uniform(
            self.config['request_delay']['min'],
            self.config['request_delay']['max']
        )
        self.logger.debug(f"随机延时: {delay:.2f}秒")
        await asyncio.sleep(delay)
    
    def _get_random_user_agent(self) -> str:
        """获取随机User-Agent"""
        return random.choice(self.config['user_agents'])
    
    async def retry_operation(self, operation, max_retries: int = None, *args, **kwargs):
        """重试操作"""
        if max_retries is None:
            max_retries = self.config['max_retries']
        
        last_exception = None
        
        for attempt in range(max_retries + 1):
            try:
                return await operation(*args, **kwargs)
            except Exception as e:
                last_exception = e
                if attempt < max_retries:
                    wait_time = 2 ** attempt  # 指数退避
                    self.logger.warning(f"操作失败，{wait_time}秒后重试 (第{attempt + 1}次): {e}")
                    await asyncio.sleep(wait_time)
                else:
                    self.logger.error(f"操作最终失败，已重试{max_retries}次: {e}")
        
        raise last_exception
    
    @property
    def is_ready(self) -> bool:
        """检查浏览器是否就绪"""
        return self.page is not None and not self.page.is_closed()


# 上下文管理器支持
class BrowserContextManager:
    """浏览器上下文管理器"""
    
    def __init__(self, headless: bool = True):
        self.headless = headless
        self.browser_manager = BrowserManager()
    
    async def __aenter__(self):
        await self.browser_manager.start(self.headless)
        return self.browser_manager
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.browser_manager.close()
